#!/usr/bin/perl -w
package GW::GWTemplate;
# This package will decode a guild wars template into skills, attributes, and whatever other information is necessary

use strict;
use Data::Dumper;

my @base64 = qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + /);
my %index = map{$base64[$_], $_} (0..63);

sub new {
	my($type,$code) = @_;
	default(\$code,"OwZiowjMpA5LYLsIWDq/8WCAA");
	my $self = {
		code => $code,
	};
	bless($self,$type);
	$self->load();
	return $self;
}

sub load {
	my($self) = @_;
	my $bin = "";
	foreach (split(//,$self->{code})) {
		my $binstr = dec2bin($index{$_});
		$binstr = reverse($binstr);
		$bin = $bin.$binstr;
	}
	eval {
		$bin =~ s/^0111//;
		my $version = $self->readBytes(\$bin,4);
		return 0 if $version != 0;
		print "Version 0\n";
		my $bits_per_profession_id = $self->readBytes(\$bin,2) * 2 + 4;
		print "Bits per profession id = $bits_per_profession_id\n";
		my $primary_profession = $self->readBytes(\$bin,$bits_per_profession_id);
		print "Primary profession = $primary_profession\n";
		my $secondary_profession = $self->readBytes(\$bin,$bits_per_profession_id);
		print "Secondary profession = $secondary_profession\n";
		my $num_attributes = $self->readBytes(\$bin,4);
		print "Attribute Count = $num_attributes\n";
		my $bits_per_attribute_id = $self->readBytes(\$bin,4) + 4;
		print "Bits per attribute id = $bits_per_attribute_id\n";
		my $attributes = {};
		for ( my $i = 0; $i < $num_attributes; $i++ ) {
			my $attribute = $self->readBytes(\$bin,$bits_per_attribute_id);
			my $value = $self->readBytes(\$bin,4);
			$attributes->{$attribute} = $value;
		}
		print Dumper($attributes);
		my $skill_bit = $self->readBytes(\$bin,4) + 8;
		my @skills = ();
		for(0..7) {
			push (@skills, $self->readBytes(\$bin,$skill_bit));
		}
		print Dumper(@skills);
	} or do {
		print $@;
	}
}

sub readBytes {
	my($self,$str,$bytes) = @_;
 	my $byteString = substr $$str, 0, $bytes;
	$$str = substr $$str, $bytes;
	$byteString = reverse $byteString;
	return bin2dec( $byteString );
}
# Static functions...


sub default {
	my($var, $val) = @_;
	if ( $$var ) {
		return;
	}
	$$var = $val;
}

sub dec2bin {
	my $pad = 6;
	my $str = unpack("B32", pack("N",shift));
	if ( $pad ) {
		$str = substr $str, -$pad;
	} else {
		$str =~ s/^0+(?=\d)//;
	}
	return $str;
}
sub bin2dec { 
	return unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}
1;
